#include <ptgui/ptgui.h>
#include <ptgui/list.h>

void ptgui_list_init(struct ptgui_list_node *l)
{
	l->next = (struct ptgui_list_node *)0;
}

void ptgui_list_append(struct ptgui_list_node *l, struct ptgui_list_node *n)
{
	struct ptgui_list_node *node;

	node = l;
	while (node->next)
		node = node->next;

	/* append the node to the tail */
	node->next = n;
	n->next = (struct ptgui_list_node *)0;
}

void ptgui_list_insert(struct ptgui_list_node *l, struct ptgui_list_node *n)
{
	n->next = l->next;
	l->next = n;
}

struct ptgui_list_node * ptgui_list_remove(struct ptgui_list_node *l, struct ptgui_list_node *n)
{
	/* remove slist head */
	struct ptgui_list_node *node = l;
	while (node->next && node->next != n)
		node = node->next;

	/* remove node */
	if (node->next != (struct ptgui_list_node *)0) {
		node->next = node->next->next;
	}

	return l;
}   	 

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/	
void __ptgui_dlist_add(struct ptgui_dlist_node *new, struct ptgui_dlist_node *prev, struct ptgui_dlist_node *next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}

/**
* ptgui_dlist_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
void ptgui_dlist_add(struct ptgui_dlist_node *new, struct ptgui_dlist_node *head)
{
	__ptgui_dlist_add(new, head, head->next);
}

/**
* ptgui_dlist_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
void ptgui_dlist_add_tail(struct ptgui_dlist_node *new, struct ptgui_dlist_node *head)
{
	__ptgui_dlist_add(new, head->prev, head);
}

/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
void __ptgui_dlist_del(struct ptgui_dlist_node *prev, struct ptgui_dlist_node *next)
{
	next->prev = prev;
	prev->next = next;
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
void ptgui_dlist_del(struct ptgui_dlist_node *entry)
{
	__ptgui_dlist_del(entry->prev, entry->next);
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
}

/**
* ptgui_dlist_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
void ptgui_dlist_del_init(struct ptgui_dlist_node *entry)
{
	__ptgui_dlist_del(entry->prev, entry->next);
	PTGUI_INIT_LIST_HEAD(entry);
}

/**
* ptgui_dlist_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
void ptgui_dlist_move(struct ptgui_dlist_node *list, struct ptgui_dlist_node *head)
{
	__ptgui_dlist_del(list->prev, list->next);
	ptgui_dlist_add(list, head);
}

/**
* ptgui_dlist_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
void ptgui_dlist_move_tail(struct ptgui_dlist_node *list, struct ptgui_dlist_node *head)
{
	__ptgui_dlist_del(list->prev, list->next);
	ptgui_dlist_add_tail(list, head);
}

/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
int ptgui_dlist_empty(const struct ptgui_dlist_node *head)
{
	return head->next == head;
}

/**
* list_empty_careful - tests whether a list is
* empty _and_ checks that no other CPU might be
* in the process of still modifying either member
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
* @head: the list to test.
*/
int ptgui_dlist_empty_careful(const struct ptgui_dlist_node *head)
{
	struct ptgui_dlist_node *next = head->next;
	return (next == head) && (next == head->prev);
}

void __ptgui_dlist_splice(struct ptgui_dlist_node *list, struct ptgui_dlist_node *head)
{
	struct ptgui_dlist_node *first = list->next;
	struct ptgui_dlist_node *last = list->prev;
	struct ptgui_dlist_node *at = head->next;

	first->prev = head;
	head->next = first;

	last->next = at;
	at->prev = last;
}

/**
* ptgui_dlist_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
void ptgui_dlist_splice(struct ptgui_dlist_node *list, struct ptgui_dlist_node *head)
{
	if (!ptgui_dlist_empty(list)) {
		__ptgui_dlist_splice(list, head);
	}
}

/**
* ptgui_dlist_splice_init - join two lists and reinitialize the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialized
*/
void ptgui_dlist_splice_init(struct ptgui_dlist_node *list, struct ptgui_dlist_node *head)
{
	if (!ptgui_dlist_empty(list)) {
		__ptgui_dlist_splice(list, head);
		PTGUI_INIT_LIST_HEAD(list);
	}
}

int ptgui_hlist_unhashed(const struct ptgui_hlist_node *h)
{
	return !h->pprev;
}

int ptgui_hlist_empty(const struct ptgui_hlist_head *h)
{
	return !h->first;
}

void __ptgui_hlist_del(struct ptgui_hlist_node *n)
{
	struct ptgui_hlist_node *next = n->next;
	struct ptgui_hlist_node **pprev = n->pprev;
	*pprev = next;
	if (next) {
		next->pprev = pprev;
	}
}

void ptgui_hlist_del(struct ptgui_hlist_node *n)
{
	__ptgui_hlist_del(n);
	n->next = LIST_POISON1;
	n->pprev = LIST_POISON2;
}

void ptgui_hlist_del_init(struct ptgui_hlist_node *n)
{
	if (n->pprev) {
		__ptgui_hlist_del(n);
		PTGUI_INIT_HLIST_NODE(n);
	}
}

void ptgui_hlist_add_head(struct ptgui_hlist_node *n, struct ptgui_hlist_head *h)
{
	struct ptgui_hlist_node *first = h->first;
	n->next = first;
	if (first) {
		first->pprev = &n->next;
	}
	h->first = n;
	n->pprev = &h->first;
}

void ptgui_hlist_add_before(struct ptgui_hlist_node *n, struct ptgui_hlist_node *next)
{
	n->pprev = next->pprev;
	n->next = next;
	next->pprev = &n->next;
	*(n->pprev) = n;
}

void ptgui_hlist_add_after(struct ptgui_hlist_node *n, struct ptgui_hlist_node *next)
{
	next->next = n->next;
	n->next = next;
	next->pprev = &n->next;

	if (next->next) {
		next->next->pprev = &next->next;
	}
}
